package com.eshop.gen.utils;

import org.slf4j.LoggerFactory;
import java.io.Writer;
import cn.hutool.extra.template.TemplateException;
import java.io.FileWriter;
import org.springframework.util.ObjectUtils;
import cn.hutool.core.util.StrUtil;
import com.eshop.utils.StringUtils;
import java.time.LocalDate;
import java.io.IOException;
import com.eshop.utils.FileUtil;
import java.io.File;
import cn.hutool.extra.template.Template;
import java.util.Iterator;
import cn.hutool.extra.template.TemplateEngine;
import java.util.HashMap;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.extra.template.TemplateConfig;
import java.util.Map;
import com.eshop.gen.domain.GenConfig;
import com.eshop.gen.domain.ColumnConfig;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;

public class GenUtil
{
    private static final Logger log;
    private static final String DATE = "Date";
    private static final String BIGDECIMAL = "BigDecimal";
    public static final String PK = "PRI";
    public static final String EXTRA = "auto_increment";
    
    private static List<String> getAdminTemplateNames() {
        final List<String> templateNames = new ArrayList<String>();
        templateNames.add("EntityP");
        templateNames.add("DtoP");
        templateNames.add("MapperP");
        templateNames.add("ControllerP");
        templateNames.add("QueryCriteriaP");
        templateNames.add("ServiceP");
        templateNames.add("ServiceImplP");
        return templateNames;
    }
    
    private static List<String> getFrontTemplateNames() {
        final List<String> templateNames = new ArrayList<String>();
        templateNames.add("index");
        templateNames.add("api");
        return templateNames;
    }
    
    public static List<Map<String, Object>> preview(final List<ColumnConfig> columns, final GenConfig genConfig) {
        final Map<String, Object> genMap = getGenMap(columns, genConfig);
        final List<Map<String, Object>> genList = new ArrayList<Map<String, Object>>();
        List<String> templates = getAdminTemplateNames();
        final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        for (final String templateName : templates) {
            final Map<String, Object> map = new HashMap<String, Object>(1);
            final Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
            map.put("content", template.render((Map)genMap));
            map.put("name", templateName);
            genList.add(map);
        }
        templates = getFrontTemplateNames();
        for (final String templateName : templates) {
            final Map<String, Object> map = new HashMap<String, Object>(1);
            final Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
            map.put(templateName, template.render((Map)genMap));
            map.put("content", template.render((Map)genMap));
            map.put("name", templateName);
            genList.add(map);
        }
        return genList;
    }
    
    public static String download(final List<ColumnConfig> columns, final GenConfig genConfig) throws IOException {
        final String tempPath = System.getProperty("java.io.tmpdir") + "yshop-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
        final Map<String, Object> genMap = getGenMap(columns, genConfig);
        final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        List<String> templates = getAdminTemplateNames();
        for (final String templateName : templates) {
            final Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
            final String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), tempPath + "yshop" + File.separator);
            assert filePath != null;
            final File file = new File(filePath);
            if (!genConfig.getCover() && FileUtil.exist(file)) {
                continue;
            }
            genFile(file, template, genMap);
        }
        templates = getFrontTemplateNames();
        for (final String templateName : templates) {
            final Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
            final String path = tempPath + "yshop-rest" + File.separator;
            final String apiPath = path + "src" + File.separator + "api" + File.separator;
            final String srcPath = path + "src" + File.separator + "views" + File.separator + genMap.get("changeClassName").toString() + File.separator;
            final String filePath2 = getFrontFilePath(templateName, apiPath, srcPath, genMap.get("changeClassName").toString());
            assert filePath2 != null;
            final File file2 = new File(filePath2);
            if (!genConfig.getCover() && FileUtil.exist(file2)) {
                continue;
            }
            genFile(file2, template, genMap);
        }
        return tempPath;
    }
    
    public static void generatorCode(final List<ColumnConfig> columnInfos, final GenConfig genConfig) throws IOException {
        final Map<String, Object> genMap = getGenMap(columnInfos, genConfig);
        final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        List<String> templates = getAdminTemplateNames();
        for (final String templateName : templates) {
            final Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
            final String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), System.getProperty("user.dir"));
            assert filePath != null;
            final File file = new File(filePath);
            if (!genConfig.getCover() && FileUtil.exist(file)) {
                continue;
            }
            genFile(file, template, genMap);
        }
        templates = getFrontTemplateNames();
        for (final String templateName : templates) {
            final Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
            final String filePath = getFrontFilePath(templateName, genConfig.getApiPath(), genConfig.getPath(), genMap.get("changeClassName").toString());
            assert filePath != null;
            final File file = new File(filePath);
            if (!genConfig.getCover() && FileUtil.exist(file)) {
                continue;
            }
            genFile(file, template, genMap);
        }
    }
    
    private static Map<String, Object> getGenMap(final List<ColumnConfig> columnInfos, final GenConfig genConfig) {
        final Map<String, Object> genMap = new HashMap<String, Object>(16);
        genMap.put("apiAlias", genConfig.getApiAlias());
        genMap.put("package", genConfig.getPack());
        genMap.put("moduleName", genConfig.getModuleName());
        genMap.put("author", genConfig.getAuthor());
        genMap.put("date", LocalDate.now().toString());
        genMap.put("tableName", genConfig.getTableName());
        String className = StringUtils.toCapitalizeCamelCase(genConfig.getTableName());
        String changeClassName = StringUtils.toCamelCase(genConfig.getTableName());
        if (StringUtils.isNotEmpty((CharSequence)genConfig.getPrefix())) {
            className = StringUtils.toCapitalizeCamelCase(StrUtil.removePrefix((CharSequence)genConfig.getTableName(), (CharSequence)genConfig.getPrefix()));
            changeClassName = StringUtils.toCamelCase(StrUtil.removePrefix((CharSequence)genConfig.getTableName(), (CharSequence)genConfig.getPrefix()));
        }
        genMap.put("className", className);
        genMap.put("changeClassName", changeClassName);
        genMap.put("hasDateTime", false);
        genMap.put("hasImages", false);
        genMap.put("queryHasDateTime", false);
        genMap.put("hasBigDecimal", false);
        genMap.put("queryHasBigDecimal", false);
        genMap.put("hasQuery", false);
        genMap.put("auto", false);
        genMap.put("hasDict", false);
        genMap.put("hasDateAnnotation", false);
        final List<Map<String, Object>> columns = new ArrayList<Map<String, Object>>();
        final List<Map<String, Object>> queryColumns = new ArrayList<Map<String, Object>>();
        final List<String> dicts = new ArrayList<String>();
        final List<Map<String, Object>> betweens = new ArrayList<Map<String, Object>>();
        final List<Map<String, Object>> isNotNullColumns = new ArrayList<Map<String, Object>>();
        for (final ColumnConfig column : columnInfos) {
            final Map<String, Object> listMap = new HashMap<String, Object>(16);
            listMap.put("remark", column.getRemark());
            listMap.put("columnKey", column.getKeyType());
            final String colType = ColUtil.cloToJava(column.getColumnType());
            final String changeColumnName = StringUtils.toCamelCase(column.getColumnName().toString());
            final String capitalColumnName = StringUtils.toCapitalizeCamelCase(column.getColumnName().toString());
            if ("PRI".equals(column.getKeyType())) {
                genMap.put("pkColumnType", colType);
                genMap.put("pkChangeColName", changeColumnName);
                genMap.put("pkCapitalColName", capitalColumnName);
            }
            if ("Images".equals(column.getFormType())) {
                genMap.put("hasImages", true);
            }
            if ("Date".equals(colType)) {
                genMap.put("hasDateTime", true);
            }
            if ("BigDecimal".equals(colType)) {
                genMap.put("hasBigDecimal", true);
            }
            if ("auto_increment".equals(column.getExtra())) {
                genMap.put("auto", true);
            }
            if (StringUtils.isNotBlank((CharSequence)column.getDictName())) {
                genMap.put("hasDict", true);
                dicts.add(column.getDictName());
            }
            listMap.put("columnType", colType);
            listMap.put("columnName", column.getColumnName());
            listMap.put("istNotNull", column.getNotNull());
            listMap.put("columnShow", column.getListShow());
            listMap.put("formShow", column.getFormShow());
            listMap.put("formType", StringUtils.isNotBlank((CharSequence)column.getFormType()) ? column.getFormType() : "Input");
            listMap.put("changeColumnName", changeColumnName);
            listMap.put("capitalColumnName", capitalColumnName);
            listMap.put("dictName", column.getDictName());
            listMap.put("dateAnnotation", column.getDateAnnotation());
            if (StringUtils.isNotBlank((CharSequence)column.getDateAnnotation())) {
                genMap.put("hasDateAnnotation", true);
            }
            if (column.getNotNull()) {
                isNotNullColumns.add(listMap);
            }
            if (!StringUtils.isBlank((CharSequence)column.getQueryType())) {
                listMap.put("queryType", column.getQueryType());
                genMap.put("hasQuery", true);
                if ("Date".equals(colType)) {
                    genMap.put("queryHasDateTime", true);
                }
                if ("BigDecimal".equals(colType)) {
                    genMap.put("queryHasBigDecimal", true);
                }
                if ("between".equalsIgnoreCase(column.getQueryType())) {
                    betweens.add(listMap);
                }
                else {
                    queryColumns.add(listMap);
                }
            }
            columns.add(listMap);
        }
        genMap.put("columns", columns);
        genMap.put("queryColumns", queryColumns);
        genMap.put("dicts", dicts);
        genMap.put("betweens", betweens);
        genMap.put("isNotNullColumns", isNotNullColumns);
        return genMap;
    }
    
    private static String getAdminFilePath(final String templateName, final GenConfig genConfig, final String className, final String rootPath) {
        final String projectPath = rootPath + File.separator + genConfig.getModuleName();
        String packagePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
        if (!ObjectUtils.isEmpty((Object)genConfig.getPack())) {
            packagePath = packagePath + genConfig.getPack().replace(".", File.separator) + File.separator;
        }
        if ("Entity".equals(templateName)) {
            return packagePath + "domain" + File.separator + className + ".java";
        }
        if ("EntityP".equals(templateName)) {
            return packagePath + "domain" + File.separator + className + ".java";
        }
        if ("Controller".equals(templateName)) {
            return packagePath + "rest" + File.separator + className + "Controller.java";
        }
        if ("ControllerP".equals(templateName)) {
            return packagePath + "rest" + File.separator + className + "Controller.java";
        }
        if ("Service".equals(templateName)) {
            return packagePath + "service" + File.separator + className + "Service.java";
        }
        if ("ServiceP".equals(templateName)) {
            return packagePath + "service" + File.separator + className + "Service.java";
        }
        if ("ServiceImpl".equals(templateName)) {
            return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }
        if ("ServiceImplP".equals(templateName)) {
            return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }
        if ("Dto".equals(templateName)) {
            return packagePath + "service" + File.separator + "dto" + File.separator + className + "Dto.java";
        }
        if ("DtoP".equals(templateName)) {
            return packagePath + "service" + File.separator + "dto" + File.separator + className + "Dto.java";
        }
        if ("QueryCriteria".equals(templateName)) {
            return packagePath + "service" + File.separator + "dto" + File.separator + className + "QueryCriteria.java";
        }
        if ("QueryCriteriaP".equals(templateName)) {
            return packagePath + "service" + File.separator + "dto" + File.separator + className + "QueryCriteria.java";
        }
        if ("Mapper".equals(templateName)) {
            return packagePath + "service" + File.separator + "mapper" + File.separator + className + "Mapper.java";
        }
        if ("MapperP".equals(templateName)) {
            return packagePath + "service" + File.separator + "mapper" + File.separator + className + "Mapper.java";
        }
        if ("Repository".equals(templateName)) {
            return packagePath + "repository" + File.separator + className + "Repository.java";
        }
        return null;
    }
    
    private static String getFrontFilePath(final String templateName, final String apiPath, final String path, final String apiName) {
        if ("api".equals(templateName)) {
            return apiPath + File.separator + apiName + ".js";
        }
        if ("index".equals(templateName)) {
            return path + File.separator + "index.vue";
        }
        return null;
    }
    
    private static void genFile(final File file, final Template template, final Map<String, Object> map) throws IOException {
        Writer writer = null;
        try {
            FileUtil.touch(file);
            writer = new FileWriter(file);
            template.render((Map)map, writer);
        }
        catch (TemplateException ex) {}
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            assert writer != null;
            writer.close();
        }
    }
    
    static {
        log = LoggerFactory.getLogger((Class)GenUtil.class);
    }
}
